package com.wzy.shiro;

import com.wzy.entity.SysMenuEntity;
import com.wzy.entity.SysRoleEntity;
import com.wzy.entity.SysUserEntity;
import com.wzy.service.SysMenuService;
import com.wzy.service.SysRoleService;
import com.wzy.service.SysUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 实现授权
     *
     * 因为Shiro中配置多个 Realm，所以身份信息可能就有多个；
     * 因此其提供了 PrincipalCollection 用于聚合这些身份信息。
     * @param principalCollection
     * @return
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //获取用户
        //获取用户的输入的账号.
        SysUserEntity sysUserEntity = (SysUserEntity) principalCollection.getPrimaryPrincipal();

        //从数据库获取角色信息和权限信息
        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();

        List<SysRoleEntity> roleList = sysRoleService.selectSysRoleByUserId(sysUserEntity.getUserId());

        for (SysRoleEntity role:roleList){
            roles.add(role.getRoleName());
            List<SysMenuEntity> menuEntityList = sysMenuService.selectSysMenuByRoleId(role.getRoleId());
            for (SysMenuEntity menu:menuEntityList){
                permissions.add(menu.getPerms());
            }
        }

        //创建SimpleAuthorizationInfo对象，设置角色和权限，并返回
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);

        return authorizationInfo;
    }

    /**
     * 实现认证
     *
     * 返回一个AuthenticationInfo对象
     * AuthenticationInfo对象中存储的是主体（Subject）的身份认证信息。
     * Shiro会调用CredentialsMatcher对象的doCredentialsMatch方法对AuthenticationInfo对象和AuthenticationToken进行匹配。
     * 匹配成功则表示主体（Subject）认证成功，否则表示认证失败。
     * 一般返回 SimpleAuthenticationInfo 即可。
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户的输入的账号.
        String username = (String) authenticationToken.getPrincipal();
        //通过username从数据库中查找 User对象，如果找到进行验证
        SysUserEntity user = sysUserService.selectUserByName(username);
        //判断账号是否存在
        if (user == null) {
            throw new UnknownAccountException();
        }
        //判断账号是否被冻结
        if (user.getState()==null||user.getState().equals("PROHIBIT")){
            throw new LockedAccountException();
        }
        //进行验证
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user,                    //用户名
                user.getPassword(),      //密码
                ByteSource.Util.bytes(user.getSalt()), //设置盐值
                this.getName()
        );
        return authenticationInfo;
    }
}
